#include "stdafx.h"
#include "ref_sheet.h"
#include "..\NSRefDataLib\KeyGenerator.h"
#include "NSRefDataToolDoc.h"

RefSheet::~RefSheet()
{
	Reset();
}
	
bool RefSheet::Init(ExcelLibrary::ISheet* sheet, CNSRefDataToolDoc* doc)
{
	Reset();

	// create columns
	unsigned long column_idx = 0;
	unsigned long column_count = sheet->GetColumnCount();
	ExcelLibrary::IColumn* excel_column = NULL;
	const wchar_t* column_name = NULL;
	LIST_COLUMNS::iterator pk_column = columns_.end();
	for (; column_idx < column_count; ++column_idx)
	{
		excel_column = sheet->GetColumn(column_idx);
		if (excel_column == NULL) {
			Log log(Log::Warning);
			log.append(name_);
			log.append(L" column count mismatch(");
			std::wostringstream idx_string;
			idx_string << column_idx;
			idx_string << ":";
			idx_string << column_count;
			log.append(idx_string.str());
			log.append(L")");
			doc->WriteLog(log);
			column_count = column_idx;
			break;
		}

		column_name = excel_column->GetStringValue();

		switch (*column_name)
		{
		case Expression_Description:
			columns_.push_back(NULL);
			break;
		case Expression_PrimaryKey:
			{
				if (pk_column != columns_.end()) {
					return false;
				}
				++column_name;
				pk_column = columns_.insert(pk_column, new Column(column_name));
			}
			break;
		case Expression_NoDBPatch:
			++column_name;
			columns_.push_back(new Column(column_name, false));
			break;
		default:
			columns_.push_back(new Column(column_name));
			break;
		}

		excel_column->Release();
	}

	if (!sheet->MoveNextRow()) {
		return false;
	}

	// batch data
	LIST_COLUMNS::iterator column_iter = columns_.begin();
	Column* column = NULL;
	const wchar_t* column_value = NULL;

	unsigned long row_count = 0;
	row_count_ = sheet->GetRowCount() - 1;
	if (row_count_ > 0) {
		do {
			bool end_row = true;
			for (column_idx = 0; column_idx < column_count; ++column_idx, ++column_iter) {
				column = (*column_iter);
				if (column != NULL) {
					excel_column = sheet->GetColumn(column_idx);
					
					if (excel_column != NULL) {
						column_value = excel_column->GetStringValue();
						if (column_value == NULL) {
							excel_column->Release();
							return false;
						}
						column->set_data(new Column::Data(column_value));
						excel_column->Release();
						end_row = false;
					} else if (!end_row) {
						column->set_data(NULL);
					}
				}
			}

			if (end_row) {
				row_count_ = row_count;
				break;
			}

			if (!sheet->MoveNextRow()) {
				return false;
			}
			++row_count;

			column_iter = columns_.begin();

		} while (!sheet->EndOfRow());
	}

	// create pk column
	if (pk_column != columns_.end()) {
		CRC32 crc;
		crc.Initialize();

		column = (*pk_column);

		Column* idx_column = new Column(L"idx");
		columns_.insert(pk_column, idx_column);

		Column::VECTOR_DATAS datas = column->datas();
		Column::VECTOR_DATAS::iterator data_end = datas.end();
		unsigned long unique_idx = 0;
		const wchar_t* column_value = NULL;
		for (Column::VECTOR_DATAS::iterator data_iter = datas.begin(); data_iter != data_end; ++data_iter) {
			USES_CONVERSION;
			column_value = (*data_iter)->value();
			char* pk = W2A(column_value);
			while (*column_value != '\0') {
				if(*column_value >= 'a' && *column_value <= 'z') {
					Log log(Log::Error);
					log.append(name_);
					log.append(L" ");
					log.append(column->name());
					log.append(L" ");
					log.append((*data_iter)->value());
					log.append(L" exist lowercase ");
					doc->WriteLog(log);
					return false;
				}
				++column_value;
			}
			unique_idx = crc.Generate32(reinterpret_cast<LPBYTE>(pk), lstrlenA(pk));
			Column::Data* idx_data = new Column::Data(bstr_t(unique_idx));
			idx_column->set_data(idx_data);

			std::pair<MAP_PK_DATAS::iterator, bool> ret;
			ret = pk_datas_.insert(MAP_PK_DATAS::value_type((*data_iter)->value(), idx_data));
			if (!ret.second) {

				Log log(Log::Error);
				log.append(L" codename duplicated..! : ");
				log.append((*data_iter)->value());
				doc->WriteLog(log);

				return false;
			}
		}
	}

	// null column erase
	LIST_COLUMNS::iterator column_end = columns_.end();
	for (column_iter = columns_.begin(); column_iter != column_end;) {
		if ((*column_iter) == NULL) {
			column_iter = columns_.erase(column_iter);
		} else {
			++column_iter;
		}
	}

	sheet->Release();

	return true;
}

void RefSheet::Reset()
{
	LIST_COLUMNS::iterator column_end = columns_.end();
	for (LIST_COLUMNS::iterator column_iter = columns_.begin(); column_iter != column_end; ++column_iter) {
		delete (*column_iter);
	}
	columns_.clear();
	pk_datas_.clear();
	row_count_ = 0;
}